package com.infolab.aims.web;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jxl.Sheet;
import jxl.Workbook;
import jxl.WorkbookSettings;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.infolab.aims.GlobalConstant;
import com.infolab.aims.common.AbstractController;
import com.infolab.aims.common.CommonUtil;
import com.infolab.aims.common.InQueryHelper;
import com.infolab.aims.common.ParameterDateQueryHelper;
import com.infolab.aims.common.bean.SearchCriteria;
import com.infolab.aims.common.bean.SearchResult;
import com.infolab.aims.common.exception.ResourceNotFoundException;
import com.infolab.aims.domain.Location;
import com.infolab.aims.domain.asset.AssetComponent;
import com.infolab.aims.domain.asset.AssetModel;
import com.infolab.aims.domain.asset.AssetTransaction;
import com.infolab.aims.domain.asset.AssetTransactionItem;
import com.infolab.aims.service.intf.AssetModelService;
import com.infolab.aims.service.intf.AssetTransactionFacadeService;
import com.infolab.aims.service.intf.AssetTransactionService;


@Controller
@RequestMapping("/stockAdjustment")
@SessionAttributes(value=StockAdjustmentController.SESSION_SEARCH_CRITERIA)
public class StockAdjustmentController extends AbstractController {
	
	public static final String SESSION_SEARCH_CRITERIA ="searchCriteria";
	public static final String CONTEXT_PATH ="/stockAdjustment";
	public static final String JSP_MAIN_FORM="stockAdjustmentForm";
	public static final String JSP_MAIN_COMP_FORM="stockAdjustmentComponentForm";
	public static final String JSP_MAIN_SEARCH="stockAdjustmentSearch";

	Log logger = LogFactory.getLog(getClass());
	
	@Autowired
	AssetTransactionFacadeService assetTransactionFacadeService;
	
	@Autowired
	AssetTransactionService assetTransactionService;
	
	@Autowired
	AssetModelService assetModelService;
	
	@RequestMapping(value={"importEquipment"}, method = RequestMethod.POST)
	public @ResponseBody String importEquipment(Model model,HttpServletRequest request,HttpServletResponse response) {

		HttpHeaders responseHeaders = new HttpHeaders();
		responseHeaders.add("Content-Type", "text/html");
		
		String type = request.getParameter("assetTransactionSubType");

		List<AssetTransactionItem> items = new ArrayList<AssetTransactionItem>();
		try
		{
			String filename = request.getHeader("X-File-Name");

			MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
			Iterator<String> fileNames = multipartRequest.getFileNames();
			while(fileNames.hasNext())
			{
				filename = fileNames.next();
			}
			MultipartFile multipartFile = multipartRequest.getFile(filename);

			InputStream is = multipartFile.getInputStream();

			Workbook workbook = null;
			try
			{
				List<String> equipmentsInImportedFile = new ArrayList<String>();
				WorkbookSettings ws = new WorkbookSettings();
				ws.setInitialFileSize(1);
				workbook = Workbook.getWorkbook(is);
				Sheet sheet  = workbook.getSheet(0);
				
				List<String> locationCodes = new ArrayList<String>();
				List<String> assetModelCodes = new ArrayList<String>();
				List<String> serialNos = new ArrayList<String>();
		
				for(int i=1;i<sheet.getRows();i++){
					String locationCode = sheet.getCell(0, i).getContents();
					String assetModelCode = sheet.getCell(1, i).getContents();
					String serialNo = sheet.getCell(2, i).getContents();				
					locationCodes.add(locationCode);
					assetModelCodes.add(assetModelCode);
					serialNos.add(serialNo);
				}
				
				
				InQueryHelper helper = new InQueryHelper("serialNo", serialNos);
				SearchCriteria searchCriteria = new SearchCriteria();
				searchCriteria.addSearchCriteria("serialNo", helper);
				List<String> list = assetModelService.searchSerialNoCriteria(searchCriteria);
				
				for(int i=0;i<serialNos.size();i++){
					String locationCode = locationCodes.get(i);
					String assetModelCode = assetModelCodes.get(i);
					String serialNo = serialNos.get(i);				
					Location location = findLocation(request, locationCode);
					AssetModel assetModel = findAssetModel(request, assetModelCode);
					AssetTransactionItem item = new AssetTransactionItem();
					
					//if IN check the assetEquipment is null
					boolean flag = false;
					if(StringUtils.equals(type, AssetTransaction.TRANSACTIONSUBTYPE_IN)){
					
						if(list.contains(serialNo)){
							flag = true;
						}

					}else{
						// if OUT check the assetEquipment is not null
						if(list.contains(serialNo)){
							flag = false;
						}
					}
					
					// checking duplicate serial no in the import excel sheet - code starts
					if(equipmentsInImportedFile.contains(serialNo))
					{
						flag = true;
					}						
					else
					{
						equipmentsInImportedFile.add(serialNo);
					}
	
					if(location == null){
						location = new Location();
						location.setLocationCode(locationCode);
						location.setLocationName(locationCode);
						flag = true;
					}
					
					if(assetModel == null){
						assetModel = new AssetModel();
						assetModel.setAssetModelCode(assetModelCode);
						flag = true;
					}
					
					item.setLocation(location);
					item.setAssetModel(assetModel);
					item.setSerialNo(serialNo);
					item.setDeleted(flag);
					items.add(item);

				}
			}catch(Exception e)
			{	
				logger.error(CommonUtil.getStackTrace(e));
			}finally{
				if(workbook!=null)
				{
					workbook.close();
				}
			}

			Map map = new HashMap();
			map.put("success", "true");
			map.put("result", items);

			StringWriter writer = new StringWriter();
	        ObjectMapper mapper = new ObjectMapper();
	        JsonGenerator jsonGenerator;
			try {
				jsonGenerator = mapper.getJsonFactory().createJsonGenerator(writer);
				mapper.writeValue(jsonGenerator, map);
				return writer.toString();
			} catch (IOException e) {
				logger.error(CommonUtil.getStackTrace(e));
			}
			
		
			
			
		} catch (Exception e) {
			
			logger.error(CommonUtil.getStackTrace(e));
		}
		
		return "[]";
	}
	
	@RequestMapping(value={"importComponent"}, method = RequestMethod.POST)
	public @ResponseBody String importComponent(Model model,HttpServletRequest request,HttpServletResponse response) {

		HttpHeaders responseHeaders = new HttpHeaders();
		responseHeaders.add("Content-Type", "text/html");
		String companyCode = request.getParameter("companyCode");
		String type = request.getParameter("assetTransactionSubType");
	
		List<AssetTransactionItem> items = new ArrayList<AssetTransactionItem>();
		try
		{
			String filename = request.getHeader("X-File-Name");

			MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
			Iterator<String> fileNames = multipartRequest.getFileNames();
			while(fileNames.hasNext())
			{
				filename = fileNames.next();
			}
			MultipartFile multipartFile = multipartRequest.getFile(filename);

			InputStream is = multipartFile.getInputStream();

			Workbook workbook = null;
			try
			{
				List<String> componentsInImportedFile = new ArrayList<String>();
				WorkbookSettings ws = new WorkbookSettings();
				ws.setInitialFileSize(1);
				workbook = Workbook.getWorkbook(is);
				Sheet sheet  = workbook.getSheet(0);

				for(int i=1;i<sheet.getRows();i++){
					String locationCode = sheet.getCell(0, i).getContents();
					String assetModelCode = sheet.getCell(1, i).getContents();
					if(StringUtils.isEmpty(assetModelCode) || StringUtils.isEmpty(locationCode)) continue;
					
					String qty = sheet.getCell(2, i).getContents();				
					Location location = findLocation(request, locationCode);
					AssetModel assetModel =  findAssetModel(request, assetModelCode);
					AssetTransactionItem item = new AssetTransactionItem();
					
					boolean flag = false;

					if(StringUtils.equals(type, AssetTransaction.TRANSACTIONSUBTYPE_IN)){
						//if IN check the assetModel is null
						if(assetModel == null || assetModel.getAssetModelId() == null){
							flag = true;
						}
						
						if(StringUtils.isNotEmpty(qty) && StringUtils.isNumeric(qty)){
							item.setAssetTransactionQuantity(Integer.parseInt(qty));
						}else{
							flag = true;
						}

					}else{
						// if OUT check the assetComponent quantity > output value is not null
						SearchCriteria searchCriteria = new SearchCriteria();
						searchCriteria.addSearchCriteria("companyCode", companyCode);
						searchCriteria.addSearchCriteria("locationCode", locationCode);
						searchCriteria.addSearchCriteria("assetModelCode", assetModelCode);
						List<AssetComponent> list = assetModelService.findAssetComponents(searchCriteria);
						AssetComponent assetComponent = null;
						if(CollectionUtils.isNotEmpty(list)){
							assetComponent = list.get(0);
							// check the logic
							if(assetComponent.getQuantity() != null && StringUtils.isNotEmpty(qty) && StringUtils.isNumeric(qty)){
								Integer iQty = Integer.parseInt(qty);
								if(assetComponent.getQuantity() < iQty){
									flag = true;
								}
								item.setAssetTransactionQuantity(Integer.parseInt(qty));
							}else{
								flag = true;
							}
							
						}else{
							flag = true;
						}
					}
					
				
					if(location == null){
						location = new Location();
						location.setLocationCode(locationCode);
						location.setLocationName(locationCode);
						flag = true;
					}
					
					if(assetModel == null){
						assetModel = new AssetModel();
						assetModel.setAssetModelCode(assetModelCode);
						flag = true;
					}
					
					// checking duplicate component in the import excel sheet - code starts
					String hash = companyCode+locationCode+assetModelCode;
					if(componentsInImportedFile.contains(hash))
					{
						flag = true;
					}						
					else
					{
						componentsInImportedFile.add(hash);
					}
					
					item.setLocation(location);
					item.setAssetModel(assetModel);
					item.setDeleted(flag);
					items.add(item);

				}
			}catch(Exception e)
			{	
				logger.error(CommonUtil.getStackTrace(e));
			}finally{
				if(workbook!=null)
				{
					workbook.close();
				}
			}

			Map map = new HashMap();
			map.put("success", "true");
			map.put("result", items);


			StringWriter writer = new StringWriter();
	        ObjectMapper mapper = new ObjectMapper();
	        JsonGenerator jsonGenerator;
			try {
				jsonGenerator = mapper.getJsonFactory().createJsonGenerator(writer);
				mapper.writeValue(jsonGenerator, map);
				return writer.toString();
			} catch (IOException e) {
				logger.error(CommonUtil.getStackTrace(e));
			}
			
		} catch (Exception e) {
			logger.error(CommonUtil.getStackTrace(e));
		}
		
		return "[]";
	}
	
	
	@RequestMapping(value="create", method = RequestMethod.GET)
	public String createStockAdjustment(Model model, HttpServletRequest request) {
		String assetTrancactionId = request.getParameter("assetTransactionId");
		String createType = request.getParameter("createType");
		AssetTransaction assetTransaction = new AssetTransaction();
		if(StringUtils.isNotEmpty(assetTrancactionId)){
			assetTransaction = assetTransactionService.getAssetTransaction(Integer.parseInt(assetTrancactionId));
		}
		model.addAttribute(assetTransaction);
		if(StringUtils.equals(AssetModel.ASSETTYPE_EQUIPMENT, createType) || StringUtils.isEmpty(createType)){
			return JSP_MAIN_FORM;
		}else{
			return JSP_MAIN_COMP_FORM;
		}
		
	}
	
	@RequestMapping(value="create",method=RequestMethod.POST)
	public String saveStockAdjustment(@ModelAttribute AssetTransaction assetTransaction, BindingResult result,Model model,HttpServletRequest request) {
		
		if (validateStockAdjusment(assetTransaction,result)) {	
			return JSP_MAIN_FORM;
		}
		List<AssetTransactionItem> newItems = new ArrayList<AssetTransactionItem>();
		List<AssetTransactionItem> items = assetTransaction.getAssetTransactionItems();
		if(CollectionUtils.isNotEmpty(items)){
			for(AssetTransactionItem item : items){
				item.setCompanyCode(assetTransaction.getCompanyCode());
				if(!item.isDeleted()){
					newItems.add(item);
				}
			}
		}
		assetTransaction.setAssetTransactionItems(newItems);
		
		assetTransaction.setCreatedBy(getCurrentUserName(request));
		
		prepareAuditObject(assetTransaction, request);
		
		assetTransactionService.createStockAdjustments(assetTransaction);
		setSuccessMessage(getMessageResources("success.create", "Stock Adjustment "));
		return "redirect:"+CONTEXT_PATH+"/update/" + assetTransaction.getAssetTransactionId();	
	}
	

	@RequestMapping(value={"update/{id}","detail/{id}"}, method = RequestMethod.GET)
	public String detailStockAdjustment(@PathVariable Integer id,Model model,HttpServletRequest request) {
		
		AssetTransaction assetTransaction = assetTransactionService.getAssetTransaction(id);
		
		if(assetTransaction==null) {
			throw new ResourceNotFoundException("Stock Adjustment " + id);
		}
		model.addAttribute(assetTransaction);
		if(StringUtils.equals(AssetModel.ASSETTYPE_EQUIPMENT, assetTransaction.getAssetType()) || StringUtils.isEmpty(assetTransaction.getAssetType())){
			return JSP_MAIN_FORM;
		}else{
			return JSP_MAIN_COMP_FORM;
		}
	}
	
	
	
	@ModelAttribute(RoleController.SESSION_SEARCH_CRITERIA)
	public SearchCriteria getRoleSearchCriteria()
	{
		return new SearchCriteria();
	}
	

	@RequestMapping(value="search")
	public String searchStockAdjusmtnet(@ModelAttribute(StockAdjustmentController.SESSION_SEARCH_CRITERIA) SearchCriteria searchCriteria,@ModelAttribute("currentSearchCriteria") SearchCriteria currentSearchCriteria,Model model) {
		
		if(currentSearchCriteria.getCurPage()!=null)
			searchCriteria.setCurPage(currentSearchCriteria.getCurPage());
		
		Date dateFrom = null;
		Date dateTo = null;
		
		try{
			if(!checkNullEmpty(searchCriteria.getSearchCriteria("dateFrom"))) {			 
				dateFrom = new SimpleDateFormat(GlobalConstant.DATE_FORMAT_JAVA).parse(searchCriteria.getSearchCriteria("dateFrom").toString());
			}
		}
		catch (ParseException e) {
			searchCriteria.addSearchCriteria("dateFrom", "");
		}
		
		try{
			
			if(!checkNullEmpty(searchCriteria.getSearchCriteria("dateTo"))) {			  
				dateTo= new SimpleDateFormat(GlobalConstant.DATE_FORMAT_JAVA).parse(searchCriteria.getSearchCriteria("dateTo").toString());
			}
		}
		catch (ParseException e) {
			searchCriteria.addSearchCriteria("dateTo", "");
		}	
		
		
		if(currentSearchCriteria.getCurPage()!=null)
			searchCriteria.setCurPage(currentSearchCriteria.getCurPage());
		
		if(!checkNullEmpty(dateFrom) &&  
				!checkNullEmpty(dateTo)) {
		
			searchCriteria.addSearchCriteria("dateModified", new ParameterDateQueryHelper("dateModified",dateFrom, dateTo));
		}
		
		else if(!checkNullEmpty(dateFrom) &&  
				checkNullEmpty(dateTo)){
			searchCriteria.addSearchCriteria("dateModified", new ParameterDateQueryHelper("dateModified",dateFrom, null));
		}		
			
		else if(checkNullEmpty(dateFrom) &&  
				!checkNullEmpty(dateTo)){
			searchCriteria.addSearchCriteria("dateModified", new ParameterDateQueryHelper("dateModified",null, dateTo));
		}
		
		else
		{
			searchCriteria.addSearchCriteria("dateModified", new ParameterDateQueryHelper("dateModified",null, null));
		}
		
		searchCriteria.addSearchCriteria("active", true);
		SearchResult searchResult = assetTransactionService.searchStockAdjustment(searchCriteria);
		model.addAttribute(searchResult);
		
		return JSP_MAIN_SEARCH;
	}
	
	private boolean validateStockAdjusment(AssetTransaction assetTransaction,BindingResult result)
	{	
		return result.hasErrors();
	}
	
	public boolean checkNullEmpty(Object obj){
		
		boolean flag=true;
		if(obj!=null && !obj.equals("")){
			flag = false;
		}
		return flag;
	
	
	}
	
	private void prepareAuditObject(AssetTransaction assetTransaction, HttpServletRequest request){
		/* audit start */
		if(assetTransaction.getFromLocation()!=null){
			Location fromLoc = findLocation(request, assetTransaction.getFromLocation().getLocationId());
			assetTransaction.setFromLocation(fromLoc);
		}
		if(assetTransaction.getToLocation()!=null){
			Location toLoc = findLocation(request, assetTransaction.getToLocation().getLocationId());
			assetTransaction.setToLocation(toLoc);
		}
		List<AssetTransactionItem> list = assetTransaction.getAssetTransactionItems();
		if(CollectionUtils.isNotEmpty(list)){
			for(AssetTransactionItem detail : list){
				if(detail.getAssetModel() != null && !detail.isDeleted()){
					Integer assetModelId = detail.getAssetModel().getAssetModelId();
					AssetModel tmp  = findAssetModel(request, assetModelId);
					detail.setAssetModel(tmp);
				}
			}
		}
		/* audit end */	
	}
	
}
